using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Moq;

namespace JGSY.CMS.LowCode.Platform.UnitTests.Infrastructure
{
    /// <summary>
    /// 控制器单元测试基类
    /// 提供通用的测试设施和辅助方法
    /// </summary>
    /// <typeparam name="TController">控制器类型</typeparam>
    public abstract class ControllerUnitTestBase<TController> where TController : ControllerBase
    {
        /// <summary>
        /// 模拟的日志记录器
        /// </summary>
        protected Mock<ILogger<TController>> MockLogger { get; }

        /// <summary>
        /// 被测试的控制器实例
        /// </summary>
        protected TController Controller { get; set; } = null!;

        protected ControllerUnitTestBase()
        {
            MockLogger = new Mock<ILogger<TController>>();
        }

        /// <summary>
        /// 验证操作结果类型
        /// </summary>
        /// <typeparam name="T">预期的结果类型</typeparam>
        /// <param name="result">操作结果</param>
        /// <returns>转换后的结果</returns>
        protected static T AssertActionResult<T>(IActionResult result) where T : IActionResult
        {
            Assert.IsType<T>(result);
            return (T)result;
        }

        /// <summary>
        /// 验证 OkObjectResult 并获取数据
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="result">操作结果</param>
        /// <returns>结果数据</returns>
        protected static T AssertOkObjectResult<T>(IActionResult result)
        {
            var okResult = AssertActionResult<OkObjectResult>(result);
            Assert.IsType<T>(okResult.Value);
            return (T)okResult.Value!;
        }

        /// <summary>
        /// 验证 BadRequestObjectResult 并获取错误信息
        /// </summary>
        /// <param name="result">操作结果</param>
        /// <returns>错误信息</returns>
        protected static object AssertBadRequestResult(IActionResult result)
        {
            var badRequestResult = AssertActionResult<BadRequestObjectResult>(result);
            return badRequestResult.Value!;
        }

        /// <summary>
        /// 验证日志记录
        /// </summary>
        /// <param name="logLevel">日志级别</param>
        /// <param name="times">调用次数</param>
        protected void VerifyLog(LogLevel logLevel, Times times)
        {
            MockLogger.Verify(
                x => x.Log(
                    logLevel,
                    It.IsAny<EventId>(),
                    It.Is<It.IsAnyType>((v, t) => true),
                    It.IsAny<Exception>(),
                    It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
                times);
        }

        /// <summary>
        /// 验证日志记录包含指定消息
        /// </summary>
        /// <param name="logLevel">日志级别</param>
        /// <param name="message">消息内容</param>
        protected void VerifyLogContains(LogLevel logLevel, string message)
        {
            MockLogger.Verify(
                x => x.Log(
                    logLevel,
                    It.IsAny<EventId>(),
                    It.Is<It.IsAnyType>((v, t) => v.ToString()!.Contains(message)),
                    It.IsAny<Exception>(),
                    It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
                Times.AtLeastOnce);
        }
    }
}
